#region Using References

using System;
using System.Diagnostics.Contracts;
using Beaker.OpenCube.Game.Converters;
using Beaker.OpenCube.Mapping;

#endregion

namespace Beaker.OpenCube.Game
{
	public sealed class PotionEffect
		: ObservableExpandoObject
	{
		private void ContractInvariant()
		{
			Contract.Invariant( Enum.IsDefined( typeof( PotionType ), _type ) );
			Contract.Ensures( _duration >= TimeSpan.Zero );
		}

		private PotionType _type;

		/// <summary>
		/// Gets or sets the type of the potion.
		/// </summary>
		/// <value>
		/// The type of the potion.
		/// </value>
		[Mapping( Name = "Id" )]
		public PotionType Type
		{
			get
			{
				Contract.Ensures( Enum.IsDefined( typeof( PotionType ), Contract.Result<PotionType>() ) );
				Contract.Ensures( Contract.Result<PotionType>() == _type );
				return _type;
			}
			set
			{
				Contract.Requires<ArgumentOutOfRangeException>( Enum.IsDefined( typeof( PotionType ), value ), "Should be a valid PotionType" );
				Contract.Ensures( _type == value );
				SetValue( ref _type, value );
			}
		}

		private byte _amplifier;

		/// <summary>
		/// Gets or sets the amplifier for the potion effect. 0 is level 1.
		/// </summary>
		/// <value>
		/// Thethe amplifier for the potion effect.
		/// </value>
		public byte Amplifier
		{
			get
			{
				Contract.Ensures( Contract.Result<byte>() == _amplifier );
				return _amplifier;
			}
			set
			{
				Contract.Ensures( _amplifier == value );
				SetValue( ref _amplifier, value );
			}
		}

		private TimeSpan _duration;

		/// <summary>
		/// Gets or sets the time before the effect wears off.
		/// </summary>
		/// <value>
		/// The time before the effect wears off.
		/// </value>
		[Mapping( Converter = typeof( GameTicksTimeSpanConverter ) )]
		public TimeSpan Duration
		{
			get
			{
				Contract.Ensures( Contract.Result<TimeSpan>() >= TimeSpan.Zero );
				Contract.Ensures( Contract.Result<TimeSpan>() == _duration );
				return _duration;
			}
			set
			{
				Contract.Requires<ArgumentOutOfRangeException>( value >= TimeSpan.Zero, "Duration cannot be negative." );
				Contract.Ensures( _duration == value );
				SetValue( ref _duration, value );
			}
		}

		private bool _isAmbient;

		/// <summary>
		/// Gets or sets a value indicating whether  this effect is provided by a Beacon and therefore should be less intrusive on screen.
		/// </summary>
		/// <value>
		/// <c>true</c> if this effect is provided by a Beacon and therefore should be less intrusive on screen; otherwise, <c>false</c>.
		/// </value>
		[Mapping( IsOptional = true )]
		public bool IsAmbient
		{
			get
			{
				Contract.Ensures( Contract.Result<bool>() == _isAmbient );
				return _isAmbient;
			}
			set
			{
				Contract.Ensures( _isAmbient == value );
				SetValue( ref _isAmbient, value );
			}
		}
	}
}